﻿using MQTTnet.Client;
using MQTTnet;
using MqttSample.core;

namespace MqttSample
{
    /// <summary>
    /// MqttClientWrapper
    /// </summary>
    public class MqttClientWrapper : IMqttClientWrapper
    {
        private MqttClientOption _option;
        private IMqttClient _client;
        private MqttFactory _mqttFactory;
        private IMqttCallback _callback;
        private bool _isInit = false;

        /// <summary>
        /// 标识mqttclient    
        /// </summary>
        public string Key { get; }

        /// <summary>
        /// ctor
        /// </summary>
        public MqttClientWrapper(MqttClientOption option, IMqttCallback callback)
        {
            _option = option;
            Key = _option.Key;
            _callback = callback;
            _mqttFactory = new MqttFactory();
            _client = _mqttFactory.CreateMqttClient();
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        public async Task StartAsync()
        {
            await Init();
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        public async Task UnSunscribeAsync(string topic)
        {
            try
            {
                var builder = _mqttFactory.CreateUnsubscribeOptionsBuilder().WithTopicFilter(topic);
                await _client.UnsubscribeAsync(builder.Build(), System.Threading.CancellationToken.None);
            }
            catch(Exception e)
            {
                var data = new CallbackData { Type = DataType.UnSubscribe, Message = $"取消主题【{topic}】订阅错误：{e.Message}" };
                await _callback?.OutEventDataAync(_option, data);
            }
        }

        /// <summary>
        /// disposable
        /// </summary>
        public void Dispose()
        {
            try
            {
                _client?.Dispose();
                _mqttFactory = null;
                _isInit = false;
            }
            catch { }
        }

        #region private method
        private async Task Init()
        {
            _client.ConnectedAsync += ClientConnectedAsync;
            _client.DisconnectedAsync += ClientDisconnectedAsync;
            _client.ApplicationMessageReceivedAsync += ClientApplicationMessageReceivedAsync;
            await ConnectAsync();
        }

        private async Task ConnectAsync()
        {
            var builder = _mqttFactory.CreateClientOptionsBuilder();
                //.WithCleanSession();
            builder.WithTcpServer(tcpOption =>
            {
                tcpOption.Server = _option.Host;
                tcpOption.Port = _option.Port;
            });
            if (!string.IsNullOrWhiteSpace(_option.ClientId))
            {
                builder.WithClientId(_option.ClientId);
            }

            if (!string.IsNullOrWhiteSpace(_option.User))
            {
                builder.WithCredentials(_option.User, _option.Password);
            }
            var option = builder.Build();

            try
            {
                await _client.ConnectAsync(option, System.Threading.CancellationToken.None);
            }
            catch(Exception e)
            {

                var data = new CallbackData { Type = DataType.Connect, Message = $"{(_isInit ? "重连" : "初次连接")}错误：{e.Message}" };
                await _callback?.OutEventDataAync(_option, data);
            }
        }

        private async Task SubscribeAsync()
        {
            try
            {
                var builder = _mqttFactory.CreateSubscribeOptionsBuilder();
                _option.TopicList.ForEach((topic) =>
                {
                    builder.WithTopicFilter((topicFilter) => topicFilter.WithTopic(topic));
                });
                var option = builder.Build();
                await _client.SubscribeAsync(option, System.Threading.CancellationToken.None);
            }
            catch(Exception e)
            {
                var data = new CallbackData { Type = DataType.Connect, Message = $"订阅初始化错误：{e.Message}" };
                await _callback?.OutEventDataAync(_option, data);
            }
        }

        private async Task ClientConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            _isInit = true;
            await SubscribeAsync();
            var data = new CallbackData
            {
                Type = DataType.Connect,
                Message = "mqtt连接成功"
            };
            await _callback?.OutEventDataAync(_option, data);
        }

        private async Task ClientDisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            var data = new CallbackData
            {
                Type = DataType.Connect,
                Message = $"mqtt连接断开:{arg.ReasonString}->{arg.Exception?.Message}"
            };
            await _callback?.OutEventDataAync(_option, data);
            if (_isInit)
            {
                System.Threading.SpinWait.SpinUntil(() => false, TimeSpan.FromSeconds(2));
                await ConnectAsync();
            }
        }

        private async Task ClientApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var data = new CallbackData
            {
                Type = DataType.Subscribe,
                CurrentClientId = arg.ClientId,
                Topic = arg.ApplicationMessage.Topic,
                Data = arg.ApplicationMessage.Payload,
                Message = $"接收到数据：QOS:{arg.ApplicationMessage.QualityOfServiceLevel},retain:{arg.ApplicationMessage.Retain}"
            };
            await _callback?.OutEventDataAync(_option, data);
        }
        #endregion
    }
}
